#include "xatexit_manager.h"
#include "xsys_log.h"
#include "xassert.h"
#include "xdebug.h"
#include "xallocator.h"
#include <stdlib.h>
#define XATEXIT_CHECK_VALID_PRIORITY(Priority) ((Priority)>=XATEXIT_LOWEST_PRIORITY)

namespace xge{
namespace xge_internal{
  size_t AtExitManager::kUntilNowMaxPriority = XATEXIT_LOWEST_PRIORITY-1;
  AtExitManager::ProxyQueue* AtExitManager::kProxyQueuePtr = NULL;
  AtExitManager::SystemLogCallback AtExitManager::kSystemLogCallback = NULL;
#ifdef _DEBUG
  bool AtExitManager::CheckInitializeOrNot() {
    return kProxyQueuePtr != NULL ;
  }
#endif// _DEBUG

  bool AtExitManager::Initialize() {
    // It can not initialize before
    XASSERT(!CheckInitializeOrNot());
    kProxyQueuePtr = new (XMalloc(sizeof(ProxyQueue))) ProxyQueue();
    atexit(AtExitMain);
    return true;
  }

  bool AtExitManager::RegisterProxy( AtExitProxy::AtExitProxyRoutine routine, void* argument , size_t priority ,const String& msg ) {
    XASSERT(CheckInitializeOrNot());
    XASSERT(XATEXIT_CHECK_VALID_PRIORITY(priority));
    kProxyQueuePtr->push(
      AtExitProxy(routine,argument,priority,msg)
      );
    if( kUntilNowMaxPriority < priority ) {
      kUntilNowMaxPriority = priority;
    }
    return true;
  }

  void __cdecl AtExitManager::AtExitMain() {
    SYS_LOG(INFO,false,_xT("AtExitProxy execute start!\n"));
    while( !(kProxyQueuePtr->empty()) ) {
      AtExitProxy& proxy = kProxyQueuePtr->top();
      if( !proxy.routine( proxy.argument ) ) {
        // the SYS_LOG destroy will always return true so
        // no worry about this use here
        SYS_LOG(PANIC,false,_xT("AtExitProxy execute error: %s\n"),proxy.error_msg);
      }
      kProxyQueuePtr->pop();
    }
    SYS_LOG(INFO,false,_xT("AtExitProxy execute over!\n"));
    // perform the log callback routine execution
    if(kSystemLogCallback)
      (*kSystemLogCallback)();
  }

}// namespace xge_internal
}//xge

#undef XATEXIT_CHECK_VALID_PRIORITY